package org.example;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;

public class TcpServer implements Runnable {


    Map<Integer, ConcurrentLinkedQueue<SocketChannel>> connectMap = new ConcurrentHashMap<>();


    @Override
    public void run() {
        try {

            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            // 设置为非阻塞模式
            serverSocketChannel.configureBlocking(false);
            // 绑定到本地端口
            serverSocketChannel.socket().bind(new InetSocketAddress(Config.instance.getAppTcpPort()));
            // 打开 Selector
            Selector selector = Selector.open();
            // 将 Channel 注册到 Selector，监听 OP_ACCEPT 事件
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            while (!Thread.interrupted()) {
                // 等待事件
                selector.select();

                // 处理已准备好的事件
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();

                    try {
                        if (key.isAcceptable()) {

                            ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                            SocketChannel clientChannel = serverChannel.accept();
                            if (clientChannel != null) {

                                AtomicBoolean first = new AtomicBoolean(true);
                                clientChannel.configureBlocking(false);
                                clientChannel.register(selector, SelectionKey.OP_READ, first);

                            }

                        } else if (key.isReadable()) {
                            ByteBuffer buffer = ByteBuffer.allocate(1024);
                            Object attachment = key.attachment();
                            if (attachment instanceof AtomicBoolean) {
                                AtomicBoolean first = (AtomicBoolean) attachment;
                                if (first.getAndSet(false)) {
                                    buffer = ByteBuffer.allocate(9);
                                }
                            }


                            SocketChannel clientChannel = (SocketChannel) key.channel();
                            int len = -1;
                            try {
                                len = clientChannel.read(buffer);
                            } catch (Exception e) {

                            }
                            if (len == -1) {

                                clientChannel.close();

                            } else if (len > 0) {

                                if (buffer.limit() == 9) {
                                    //完整读完5个字节
                                    while (buffer.hasRemaining()) {
                                        clientChannel.read(buffer);
                                    }
                                    buffer.flip();
                                    byte operate = buffer.get();
                                    int dstPort = buffer.getInt();
                                    int srcPort = buffer.getInt();


                                    if (operate == 0) {
                                        //请求需要连接
                                        ConcurrentLinkedQueue<SocketChannel> socketChannels = connectMap.get(dstPort);
                                        if (socketChannels == null) {
                                            ConcurrentLinkedQueue<SocketChannel> queue = new ConcurrentLinkedQueue<>();
                                            connectMap.putIfAbsent(dstPort, queue);
                                        }
                                        ConcurrentLinkedQueue<SocketChannel> channels = connectMap.get(dstPort);
                                        try {

                                            SocketChannel socketChannel = channels.poll();

                                            if(socketChannel == null){
                                                clientChannel.close();
                                            }else{
                                                //交换数据
                                                socketChannel.register(selector, SelectionKey.OP_READ, clientChannel);
                                                clientChannel.register(selector, SelectionKey.OP_READ, socketChannel);
                                            }


                                        } catch (Exception e) {
                                            e.printStackTrace();
                                        }
                                    } else {


                                        //需要的连接
                                        ConcurrentLinkedQueue<SocketChannel> socketChannels = connectMap.get(dstPort);
                                        if (socketChannels == null) {
                                            ConcurrentLinkedQueue<SocketChannel> queue = new ConcurrentLinkedQueue<>();
                                            connectMap.putIfAbsent(dstPort, queue);
                                        }
                                        ConcurrentLinkedQueue<SocketChannel> channels = connectMap.get(dstPort);
                                        channels.offer(clientChannel);


                                        //下发告诉连接成功
                                        ByteBuffer allocate = ByteBuffer.allocate(5);
                                        allocate.put(new byte[]{2});
                                        allocate.putInt(dstPort);
                                        ByteBuffer byteBuffer = buildBuff("127.0.0.1", allocate.array());
                                        SocketChannel socketChannel = ChannelContext.get(srcPort);
                                        try {
                                            socketChannel.write(byteBuffer);
                                        }catch (Exception e){
                                            e.printStackTrace();
                                        }


                                    }

                                } else {
                                    buffer.flip();

                                    SocketChannel socketChannel = (SocketChannel) attachment;
                                    socketChannel.write(buffer);
                                }

                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    iterator.remove();

                }
            }

        } catch (Exception e) {
            System.out.println("server TcpServer 线程异常结束:" + e.getMessage());
            e.printStackTrace();
        }

    }

    private ByteBuffer buildBuff(String hostAddress, byte[] bt) {
        byte[] bByte = hostAddress.getBytes();
        ByteBuffer allocate = ByteBuffer.allocate(4 + 4 + bByte.length + bt.length);
        allocate.putInt(4 + bByte.length + bt.length);
        allocate.putInt(bByte.length);
        allocate.put(bByte);
        allocate.put(bt);
        allocate.flip();
        return allocate;
    }

}
